using System;
using System.Drawing;
using UltimateDefend.Properties;
using System.Drawing.Imaging;
using System.Threading;

using System.Xml;

namespace UltimateDefend
{
    public abstract class IEnemy
    {
        #region Creep Fields
        protected int m_nHP;                    // Mau cua creep    
        protected int m_nArmor;                 // Giap cua creep
        protected int m_nMovSpeed;              // Toc do di chuyen cua creep
        protected bool m_bIsRunning = false;    // Creep dang chay hay chua
        protected int m_nCost;
        protected Point[] m_arAnchors;          // Mang diem de di chuyen
        #endregion
        #region Creep Methods
        /// <summary>
        /// Ham kiem tra creep co bi tower tieu diet hay chua
        /// </summary>
        /// <returns>return: true - da chet, false - chua chet</returns>
        public bool IsDeath()
        {
            return (m_nHP <= 0);
        }

        /// <summary>
        /// Kiem tra creep da ve dich chua
        /// </summary>
        /// <returns>bool: true-ve dich; false-chua ve dich</returns>
        public bool IsFinish()
        {
            return m_ptPosition.Equals(m_arAnchors[m_arAnchors.Length - 1]);
        }
        #endregion


        #region ..::Display Attributes::..
        protected Bitmap m_imDisplay;       // Hinh anh dung de hien thi
        protected Point m_ptPosition;       // Vi tri hien tai cua creep
        public ImageAttributes imageAttribute = new ImageAttributes();
        public int XFrame, YFrame;          // Kich thuoc khung hinh
        #endregion
        #region ..::Bitmaps::..
        static public int numFrames;            // So khung hinh cua animation
        #endregion
        #region ..::Core::..
        #region Abstract
        /// <summary>
        /// Load hinh anh hien thi tuong ung cho creep
        /// </summary>
        /// <param name="i">So thu tu cua khung hinh</param>
        /// <param name="dir">Huong di chuyen cua creep</param>
        abstract protected void LoadSprite(int i, char dir);

        /// <summary>
        /// Lay gia tri mau transparent
        /// </summary>
        abstract public void GetTransparentColor();

        #endregion
        #region ..::Methods::..
        /// <summary>
        /// Creep bat dau di chuyen
        /// </summary>
        public void StartRunning()
        {
            m_bIsRunning = true;
            int next = 1;
            int i = 0;          // i: Frame can hien thi
            int x, y;
            char dir = 'D';
            while (next < m_arAnchors.Length)
            {
                m_ptPosition = m_arAnchors[next - 1];
                if (m_arAnchors[next].X == m_ptPosition.X)
                    x = 0;
                else if (m_arAnchors[next].X > m_ptPosition.X)
                {
                    x = 1;
                    dir = 'R';      // hard code
                }
                else
                {
                    x = -1;
                    dir = 'L';      // hard code
                }
                if (m_arAnchors[next].Y == m_ptPosition.Y)
                    y = 0;
                else if (m_arAnchors[next].Y > m_ptPosition.Y)
                {
                    y = 1;
                    dir = 'D';      // hard code
                }
                else
                {
                    y = -1;
                    dir = 'U';        // hard code
                }
                while (!m_ptPosition.Equals(m_arAnchors[next]))
                {
                    i++;
                    if (i == numFrames)
                        i = 0;

                    // Load hinh anh hien thi cua creep
                    LoadSprite(i, dir);
                    // Dich chuyen creep di 1 doan x, y
                    m_ptPosition.Offset(x, y);
                    Thread.Sleep(m_nMovSpeed);
                }
                next++;
                // creep ve dich
                if (IsFinish())
                {
                    ArcadeFrm.CurrentLevel.Lives--;
                    ArcadeFrm.CurrentLevel.UpdateData();
                }
                    // creep chet
                else if (IsDeath())
                {
                    ArcadeFrm.CurrentLevel.CurrentCreeps--;
                    ArcadeFrm.CurrentLevel.Gold += m_nCost;
                    ArcadeFrm.CurrentLevel.UpdateData();
                }
            }
        }

        /// <summary>
        /// Lay khung hinh hien thi cua creep de hien thi len thiet bi
        /// </summary>
        /// <returns>Rectangle: Khung hinh hien thi hien tai cua creep</returns>
        public Rectangle GetFrame()
        {
            XFrame = m_imDisplay.Width;
            YFrame = m_imDisplay.Height;
            // Tra ve vi tri khung chu nhat
            return new Rectangle(m_ptPosition.X, m_ptPosition.Y, XFrame, YFrame);
        }

        #endregion
        #endregion

        #region Creep Properties
        /// <summary>
        /// g - Lay hinh anh hien thi cua creep
        /// </summary>
        public Bitmap Display
        {
            get { return m_imDisplay; }
        }

        /// <summary>
        /// g - ???
        /// </summary>
        public bool IsRunning
        {
            get { return m_bIsRunning; }
        }

        /// <summary>
        /// gs - Gia tri HP cua creep
        /// </summary>
        public int HP
        {
            get { return m_nHP; }
            set { m_nHP = value; }
        }

        /// <summary>
        /// gs - Gia tri armor cua creep
        /// </summary>
        public int Armor
        {
            get { return m_nArmor; }
            set { m_nArmor = value; }
        }

        /// <summary>
        /// g - So tien thu duoc sau khi giet creep
        /// </summary>
        public int Price
        {
            get { return m_nCost; }
        }

        /// <summary>
        /// g - Lay vi tri hien tai cua creep
        /// </summary>
        public Point Position
        {
            get { return m_ptPosition; }
        }
        #endregion

    }

    /// <summary>
    /// Class FootMan
    /// </summary>
    public sealed class FootMan : IEnemy
    {
        static protected int mHP;                    // Mau
        static protected int mArmor;                 // Giap
        static protected int mMovSpeed;              // Toc do di chuyen
        static protected int mCost;                  // Gia tien thu duoc khi tieu diet creep
        static protected string mName;               // Ten de hien thi, co khi ko can


        public FootMan(Point[] anchors)
        {
            m_nHP = FootMan.mHP;
            m_nArmor = FootMan.mArmor;
            m_nMovSpeed = FootMan.mMovSpeed;
            m_nCost = FootMan.mCost;

            m_arAnchors = anchors;
            m_ptPosition = anchors[0];
            // Load tu file XML
        }

        static Bitmap[] bmDown, bmUp, bmLeft, bmRight;
        /// <summary>
        /// Load tat ca bitmap len memory
        /// </summary>
        static public void LoadData(XmlTextReader reader)
        {
            // Load data form xml file

            string filename = "", location = "", frames = "", ext = "";

            if (reader.ReadToFollowing("footman"))
            {
                filename = reader.GetAttribute("filename");
                location = reader.GetAttribute("location");
                frames = reader.GetAttribute("frames");
                ext = reader.GetAttribute("ext");
            }
            // Read footman info from xml data
            reader.ReadToFollowing("HP");
            FootMan.mHP = int.Parse(reader.ReadString());

            reader.ReadToFollowing("armor");
            FootMan.mArmor = int.Parse(reader.ReadString());

            reader.ReadToFollowing("movespeed");
            FootMan.mMovSpeed = int.Parse(reader.ReadString());

            reader.ReadToFollowing("price");
            FootMan.mCost = int.Parse(reader.ReadString());

            // Load bitmaps onto memory
            numFrames = int.Parse(frames);
            FootMan.bmDown = new Bitmap[numFrames];
            FootMan.bmUp = new Bitmap[numFrames];
            FootMan.bmLeft = new Bitmap[numFrames];
            FootMan.bmRight = new Bitmap[numFrames];
            for (int i = 0; i < numFrames; i++)
            {
                FootMan.bmDown[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Down." +
                    string.Format("{0:00}.", i + 1) + ext);

                LoadFrm.nProgress += 100 / 24;

                FootMan.bmUp[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Up." +
                    string.Format("{0:00}.", i + 1) + ext);

                LoadFrm.nProgress += 100 / 24;

                FootMan.bmLeft[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Left." + 
                    string.Format("{0:00}.", i + 1) + ext);

                LoadFrm.nProgress += 100 / 24;

                FootMan.bmRight[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Right." +
                    string.Format("{0:00}.", i + 1) + ext);

                LoadFrm.nProgress += 100 / 24;
            }
        }


        /// <summary>
        /// Lay gia tri mau transparent
        /// </summary>
        public override void GetTransparentColor()
        {
            imageAttribute.SetColorKey(FootMan.bmDown[0].GetPixel(1, 1), FootMan.bmDown[0].GetPixel(1, 1));
        }


        /// <summary>
        /// Load hinh anh hien thi tuong ung cua creep
        /// </summary>
        /// <param name="i">So thu tu cua khung hinh</param>
        /// <param name="dir">Huong di chuyen cua creep</param>
        protected override void LoadSprite(int i, char dir)
        {
            switch (dir)
            {
                case 'D':
                    m_imDisplay = FootMan.bmDown[i];
                    break;
                case 'U':
                    m_imDisplay = FootMan.bmUp[i];
                    break;
                case 'L':
                    m_imDisplay = FootMan.bmLeft[i];
                    break;
                case 'R':
                    m_imDisplay = FootMan.bmRight[i];
                    break;
            }
        }
    }

    /// <summary>
    /// Class Knight/HeavyArmor
    /// </summary>
    public sealed class HeavyArmor : IEnemy
    {
        static protected int mHP;                    // Mau
        static protected int mArmor;                 // Giap
        static protected int mMovSpeed;              // Toc do di chuyen
        static protected int mCost;                  // Gia tien thu duoc khi tieu diet creep
        static protected string mName;               // Ten de hien thi, co khi ko can

        public HeavyArmor(Point[] anchors)
        {
            m_nHP = HeavyArmor.mHP;
            m_nArmor = HeavyArmor.mArmor;
            m_nMovSpeed = HeavyArmor.mMovSpeed;
            m_nCost = HeavyArmor.mCost;

            m_arAnchors = anchors;
            m_ptPosition = anchors[0];
        }


        static Bitmap[] bmDown, bmUp, bmLeft, bmRight;
        /// <summary>
        /// Load tat ca bitmap len memory
        /// </summary>
        static public void LoadData(XmlTextReader reader)
        {
            // read data form xml file
            string filename = "", location = "", frames = "", ext = "";

            if (reader.ReadToFollowing("knight"))
            {
                filename = reader.GetAttribute("filename");
                location = reader.GetAttribute("location");
                frames = reader.GetAttribute("frames");
                ext = reader.GetAttribute("ext");
            }
            // Read footman info from xml data
            reader.ReadToFollowing("HP");
            HeavyArmor.mHP = int.Parse(reader.ReadString());

            reader.ReadToFollowing("armor");
            HeavyArmor.mArmor = int.Parse(reader.ReadString());

            reader.ReadToFollowing("movespeed");
            HeavyArmor.mMovSpeed = int.Parse(reader.ReadString());

            reader.ReadToFollowing("price");
            HeavyArmor.mCost = int.Parse(reader.ReadString());


            // totally hard code
            numFrames = int.Parse(frames);
            HeavyArmor.bmDown = new Bitmap[numFrames];
            HeavyArmor.bmUp = new Bitmap[numFrames];
            HeavyArmor.bmLeft = new Bitmap[numFrames];
            HeavyArmor.bmRight = new Bitmap[numFrames];
            for (int i = 0; i < numFrames; i++)
            {
                HeavyArmor.bmDown[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Down." +
                    string.Format("{0:00}.", i + 1) + ext);

                LoadFrm.nProgress += 100 / 24;

                HeavyArmor.bmUp[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Up." +
                    string.Format("{0:00}.", i + 1) + ext);

                LoadFrm.nProgress += 100 / 24;

                HeavyArmor.bmLeft[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Left." +
                    string.Format("{0:00}.", i + 1) + ext);

                LoadFrm.nProgress += 100 / 24;

                HeavyArmor.bmRight[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Right." +
                    string.Format("{0:00}.", i + 1) + ext);

                LoadFrm.nProgress += 100 / 24;

            }
        }


        /// <summary>
        /// Lay gia tri mau transparent
        /// </summary>
        public override void GetTransparentColor()
        {
            imageAttribute.SetColorKey(HeavyArmor.bmDown[0].GetPixel(1, 1), HeavyArmor.bmDown[0].GetPixel(1, 1));
        }


        /// <summary>
        /// Load hinh anh hien thi tuong ung cua creep
        /// </summary>
        /// <param name="i">So thu tu khung hinh</param>
        /// <param name="dir">Huong di chuyen cua creep</param>
        protected override void LoadSprite(int i, char dir)
        {
            switch (dir)
            {
                case 'D':
                    m_imDisplay = HeavyArmor.bmDown[i];
                    break;
                case 'U':
                    m_imDisplay = HeavyArmor.bmUp[i];
                    break;
                case 'L':
                    m_imDisplay = HeavyArmor.bmLeft[i];
                    break;
                case 'R':
                    m_imDisplay = HeavyArmor.bmRight[i];
                    break;
            }
        }
    }

    /// <summary>
    /// Interface boss
    /// </summary>
    public abstract class IBoss : IEnemy
    {
        static protected int mHP;                    // Mau
        static protected int mArmor;                 // Giap
        static protected int mMovSpeed;              // Toc do di chuyen
        static protected int mCost;                  // Gia tien thu duoc khi tieu diet creep
        static protected string mName;               // Ten de hien thi, co khi ko can

        static protected Bitmap[] bmDown, bmUp, bmLeft, bmRight;
        /// <summary>
        /// Load tat ca bitmap len memory
        /// </summary>
        static public void LoadData(XmlTextReader reader)
        {
            // read data form xml file
            string filename = "", location = "", frames = "", ext = "";

            if (reader.ReadToFollowing("boss"))
            {
                filename = reader.GetAttribute("filename");
                location = reader.GetAttribute("location");
                frames = reader.GetAttribute("frames");
                ext = reader.GetAttribute("ext");
            }
            // Read footman info from xml data
            reader.ReadToFollowing("HP");
            IBoss.mHP = int.Parse(reader.ReadString());

            reader.ReadToFollowing("armor");
            IBoss.mArmor = int.Parse(reader.ReadString());

            reader.ReadToFollowing("movespeed");
            IBoss.mMovSpeed = int.Parse(reader.ReadString());

            reader.ReadToFollowing("price");
            IBoss.mCost = int.Parse(reader.ReadString());


            // totally hard code
            numFrames = int.Parse(frames);
            IBoss.bmDown = new Bitmap[numFrames];
            IBoss.bmUp = new Bitmap[numFrames];
            IBoss.bmLeft = new Bitmap[numFrames];
            IBoss.bmRight = new Bitmap[numFrames];
            for (int i = 0; i < numFrames; i++)
            {
                IBoss.bmDown[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Down." +
                    string.Format("{0:00}.", i + 1) + ext);

                //LoadFrm.nProgress += 100 / 24;

                IBoss.bmUp[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Up." +
                    string.Format("{0:00}.", i + 1) + ext);

                //LoadFrm.nProgress += 100 / 24;

                IBoss.bmLeft[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Left." +
                    string.Format("{0:00}.", i + 1) + ext);

                //LoadFrm.nProgress += 100 / 24;

                IBoss.bmRight[i] = new Bitmap(LoadFrm.startup +
                    location + filename + "Right." +
                    string.Format("{0:00}.", i + 1) + ext);

                //LoadFrm.nProgress += 100 / 24;

            }
        }


        /// <summary>
        /// Kha nang dac biet cua creep, chi danh cho boss
        /// </summary>
        abstract public void SpecialSkill();
    }

    /// <summary>
    /// Boss 1
    /// </summary>
    public sealed class Boss1 : IBoss
    {
        public Boss1(Point[] anchors)
        {
            m_nHP = IBoss.mHP;
            m_nArmor = IBoss.mArmor;
            m_nMovSpeed = IBoss.mMovSpeed;
            

            m_arAnchors = anchors;
            m_ptPosition = anchors[0];
        }

        /// <summary>
        /// Lay gia tri mau transparent
        /// </summary>
        public override void GetTransparentColor()
        {
            imageAttribute.SetColorKey(IBoss.bmDown[0].GetPixel(1, 1), IBoss.bmDown[0].GetPixel(1, 1));
        }

        /// <summary>
        /// Load hinh anh hien thi tuong ung cua creep
        /// </summary>
        /// <param name="i">So thu tu khung hinh</param>
        /// <param name="dir">Huong di chuyen cua creep</param>
        protected override void LoadSprite(int i, char dir)
        {
            switch (dir)
            {
                case 'D':
                    m_imDisplay = IBoss.bmDown[i];
                    break;
                case 'U':
                    m_imDisplay = IBoss.bmUp[i];
                    break;
                case 'L':
                    m_imDisplay = IBoss.bmLeft[i];
                    break;
                case 'R':
                    m_imDisplay = IBoss.bmRight[i];
                    break;
            }
        }

        public override void SpecialSkill()
        {
            m_nMovSpeed += m_nMovSpeed / 2;
        }
    }
}
